home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / initsnb.zoo / init / sh / var.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-09  |  12.9 KB  |  656 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)var.c    5.3 (Berkeley) 4/12/91";
  39. #endif /* not lint */
  40.  
  41. #ifdef __STDC__
  42. #  define __P(x) x
  43. #else
  44. #  define __P(x)
  45. #endif
  46.  
  47. /*
  48.  * Shell variables.
  49.  */
  50.  
  51. #include "shell.h"
  52. #include "output.h"
  53. #include "expand.h"
  54. #include "nodes.h"    /* for other headers */
  55. #include "eval.h"    /* defines cmdenviron */
  56. #include "exec.h"
  57. #include "syntax.h"
  58. #include "options.h"
  59. #include "mail.h"
  60. #include "var.h"
  61. #include "memalloc.h"
  62. #include "error.h"
  63. #include "mystring.h"
  64.  
  65.  
  66. #define VTABSIZE 39
  67.  
  68.  
  69. struct varinit {
  70.     struct var *var;
  71.     int flags;
  72.     char *text;
  73. };
  74.  
  75.  
  76. #if ATTY
  77. struct var vatty;
  78. #endif
  79. struct var vifs;
  80. struct var vmail;
  81. struct var vmpath;
  82. struct var vpath;
  83. struct var vps1;
  84. struct var vps2;
  85. struct var vvers;
  86. #if ATTY
  87. struct var vterm;
  88. #endif
  89.  
  90. const struct varinit varinit[] = {
  91. #if ATTY
  92.     {&vatty,    VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY="},
  93. #endif
  94.     {&vifs,    VSTRFIXED|VTEXTFIXED,        "IFS= \t\n"},
  95.     {&vmail,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL="},
  96.     {&vmpath,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH="},
  97.     {&vpath,    VSTRFIXED|VTEXTFIXED,        "PATH=:/bin:/usr/bin"},
  98.     /* 
  99.      * vps1 depends on uid
  100.      */
  101.     {&vps2,    VSTRFIXED|VTEXTFIXED,        "PS2=> "},
  102. #if ATTY
  103.     {&vterm,    VSTRFIXED|VTEXTFIXED|VUNSET,    "TERM="},
  104. #endif
  105.     {NULL,    0,                NULL}
  106. };
  107.  
  108. struct var *vartab[VTABSIZE];
  109.  
  110. STATIC void unsetvar __P((char *));
  111. STATIC struct var **hashvar __P((char *));
  112. STATIC int varequal __P((char *, char *));
  113.  
  114. /*
  115.  * Initialize the varable symbol tables and import the environment
  116.  */
  117.  
  118. #ifdef mkinit
  119. INCLUDE "var.h"
  120. INIT {
  121.     char **envp;
  122.     extern char **environ;
  123.  
  124.     initvar();
  125.     for (envp = environ ; *envp ; envp++) {
  126.         if (strchr(*envp, '=')) {
  127.             setvareq(*envp, VEXPORT|VTEXTFIXED);
  128.         }
  129.     }
  130. }
  131. #endif
  132.  
  133.  
  134. /*
  135.  * This routine initializes the builtin variables.  It is called when the
  136.  * shell is initialized and again when a shell procedure is spawned.
  137.  */
  138.  
  139. void
  140. initvar() {
  141.     const struct varinit *ip;
  142.     struct var *vp;
  143.     struct var **vpp;
  144.  
  145.     for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
  146.         if ((vp->flags & VEXPORT) == 0) {
  147.             vpp = hashvar(ip->text);
  148.             vp->next = *vpp;
  149.             *vpp = vp;
  150.             vp->text = ip->text;
  151.             vp->flags = ip->flags;
  152.         }
  153.     }
  154.     /*
  155.      * PS1 depends on uid
  156.      */
  157.     if ((vps1.flags & VEXPORT) == 0) {
  158.         vpp = hashvar("PS1=");
  159.         vps1.next = *vpp;
  160.         *vpp = &vps1;
  161.         vps1.text = getuid() ? "PS1=$ " : "PS1=# ";
  162.         vps1.flags = VSTRFIXED|VTEXTFIXED;
  163.     }
  164. }
  165.  
  166. /*
  167.  * Set the value of a variable.  The flags argument is ored with the
  168.  * flags of the variable.  If val is NULL, the variable is unset.
  169.  */
  170.  
  171. void
  172. setvar(name, val, flags)
  173.     char *name, *val;
  174.     {
  175.     char *p, *q;
  176.     int len;
  177.     int namelen;
  178.     char *nameeq;
  179.     int isbad;
  180.  
  181.     isbad = 0;
  182.     p = name;
  183.     if (! is_name(*p++))
  184.         isbad = 1;
  185.     for (;;) {
  186.         if (! is_in_name(*p)) {
  187.             if (*p == '\0' || *p == '=')
  188.                 break;
  189.             isbad = 1;
  190.         }
  191.         p++;
  192.     }
  193.     namelen = p - name;
  194.     if (isbad)
  195.         error("%.*s: is read only", namelen, name);
  196.     len = namelen + 2;        /* 2 is space for '=' and '\0' */
  197.     if (val == NULL) {
  198.         flags |= VUNSET;
  199.     } else {
  200.         len += strlen(val);
  201.     }
  202.     p = nameeq = ckmalloc(len);
  203.     q = name;
  204.     while (--namelen >= 0)
  205.         *p++ = *q++;
  206.     *p++ = '=';
  207.     *p = '\0';
  208.     if (val)
  209.         scopy(val, p);
  210.     setvareq(nameeq, flags);
  211. }
  212.  
  213.  
  214.  
  215. /*
  216.  * Same as setvar except that the variable and value are passed in
  217.  * the first argument as name=value.  Since the first argument will
  218.  * be actually stored in the table, it should not be a string that
  219.  * will go away.
  220.  */
  221.  
  222. void
  223. setvareq(s, flags)
  224.     char *s;
  225.     {
  226.     struct var *vp, **vpp;
  227.  
  228.     vpp = hashvar(s);
  229.     for (vp = *vpp ; vp ; vp = vp->next) {
  230.         if (varequal(s, vp->text)) {
  231.             if (vp->flags & VREADONLY) {
  232.                 int len = strchr(s, '=') - s;
  233.                 error("%.*s: is read only", len, s);
  234.             }
  235.             INTOFF;
  236.             if (vp == &vpath)
  237.                 changepath(s + 5);    /* 5 = strlen("PATH=") */
  238.             if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
  239.                 ckfree(vp->text);
  240.             vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
  241.             vp->flags |= flags;
  242.             vp->text = s;
  243.             if (vp == &vmpath || (vp == &vmail && ! mpathset()))
  244.                 chkmail(1);
  245.             INTON;
  246.             return;
  247.         }
  248.     }
  249.     /* not found */
  250.     vp = ckmalloc(sizeof (*vp));
  251.     vp->flags = flags;
  252.     vp->text = s;
  253.     vp->next = *vpp;
  254.     *vpp = vp;
  255. }
  256.  
  257.  
  258.  
  259. /*
  260.  * Process a linked list of variable assignments.
  261.  */
  262.  
  263. void
  264. listsetvar(list)
  265.     struct strlist *list;
  266.     {
  267.     struct strlist *lp;
  268.  
  269.     INTOFF;
  270.     for (lp = list ; lp ; lp = lp->next) {
  271.         setvareq(savestr(lp->text), 0);
  272.     }
  273.     INTON;
  274. }
  275.  
  276.  
  277.  
  278. /*
  279.  * Find the value of a variable.  Returns NULL if not set.
  280.  */
  281.  
  282. char *
  283. lookupvar(name)
  284.     char *name;
  285.     {
  286.     struct var *v;
  287.  
  288.     for (v = *hashvar(name) ; v ; v = v->next) {
  289.         if (varequal(v->text, name)) {
  290.             if (v->flags & VUNSET)
  291.                 return NULL;
  292.             return strchr(v->text, '=') + 1;
  293.         }
  294.     }
  295.     return NULL;
  296. }
  297.  
  298.  
  299.  
  300. /*
  301.  * Search the environment of a builtin command.  If the second argument
  302.  * is nonzero, return the value of a variable even if it hasn't been
  303.  * exported.
  304.  */
  305.  
  306. char *
  307. bltinlookup(name, doall)
  308.     char *name;
  309.     {
  310.     struct strlist *sp;
  311.     struct var *v;
  312.  
  313.     for (sp = cmdenviron ; sp ; sp = sp->next) {
  314.         if (varequal(sp->text, name))
  315.             return strchr(sp->text, '=') + 1;
  316.     }
  317.     for (v = *hashvar(name) ; v ; v = v->next) {
  318.         if (varequal(v->text, name)) {
  319.             if (v->flags & VUNSET
  320.              || ! doall && (v->flags & VEXPORT) == 0)
  321.                 return NULL;
  322.             return strchr(v->text, '=') + 1;
  323.         }
  324.     }
  325.     return NULL;
  326. }
  327.  
  328.  
  329.  
  330. /*
  331.  * Generate a list of exported variables.  This routine is used to construct
  332.  * the third argument to execve when executing a program.
  333.  */
  334.  
  335. char **
  336. environment() {
  337.     int nenv;
  338.     struct var **vpp;
  339.     struct var *vp;
  340.     char **env, **ep;
  341.  
  342.     nenv = 0;
  343.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  344.         for (vp = *vpp ; vp ; vp = vp->next)
  345.             if (vp->flags & VEXPORT)
  346.                 nenv++;
  347.     }
  348.     ep = env = stalloc((nenv + 1) * sizeof *env);
  349.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  350.         for (vp = *vpp ; vp ; vp = vp->next)
  351.             if (vp->flags & VEXPORT)
  352.                 *ep++ = vp->text;
  353.     }
  354.     *ep = NULL;
  355.     return env;
  356. }
  357.  
  358.  
  359. /*
  360.  * Called when a shell procedure is invoked to clear out nonexported
  361.  * variables.  It is also necessary to reallocate variables of with
  362.  * VSTACK set since these are currently allocated on the stack.
  363.  */
  364.  
  365. #ifdef mkinit
  366. MKINIT void shprocvar();
  367.  
  368. SHELLPROC {
  369.     shprocvar();
  370. }
  371. #endif
  372.  
  373. void
  374. shprocvar() {
  375.     struct var **vpp;
  376.     struct var *vp, **prev;
  377.  
  378.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  379.         for (prev = vpp ; (vp = *prev) != NULL ; ) {
  380.             if ((vp->flags & VEXPORT) == 0) {
  381.                 *prev = vp->next;
  382.                 if ((vp->flags & VTEXTFIXED) == 0)
  383.                     ckfree(vp->text);
  384.                 if ((vp->flags & VSTRFIXED) == 0)
  385.                     ckfree(vp);
  386.             } else {
  387.                 if (vp->flags & VSTACK) {
  388.                     vp->text = savestr(vp->text);
  389.                     vp->flags &=~ VSTACK;
  390.                 }
  391.                 prev = &vp->next;
  392.             }
  393.         }
  394.     }
  395.     initvar();
  396. }
  397.  
  398.  
  399.  
  400. /*
  401.  * Command to list all variables which are set.  Currently this command
  402.  * is invoked from the set command when the set command is called without
  403.  * any variables.
  404.  */
  405.  
  406. int
  407. showvarscmd(argc, argv)  char **argv; {
  408.     struct var **vpp;
  409.     struct var *vp;
  410.  
  411.     for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  412.         for (vp = *vpp ; vp ; vp = vp->next) {
  413.             if ((vp->flags & VUNSET) == 0)
  414.                 out1fmt("%s\n", vp->text);
  415.         }
  416.     }
  417.     return 0;
  418. }
  419.  
  420.  
  421.  
  422. /*
  423.  * The export and readonly commands.
  424.  */
  425.  
  426. int
  427. exportcmd(argc, argv)  char **argv; {
  428.     struct var **vpp;
  429.     struct var *vp;
  430.     char *name;
  431.     char *p;
  432.     int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
  433.  
  434.     listsetvar(cmdenviron);
  435.     if (argc > 1) {
  436.         while ((name = *argptr++) != NULL) {
  437.             if ((p = strchr(name, '=')) != NULL) {
  438.                 p++;
  439.             } else {
  440.                 vpp = hashvar(name);
  441.                 for (vp = *vpp ; vp ; vp = vp->next) {
  442.                     if (varequal(vp->text, name)) {
  443.                         vp->flags |= flag;
  444.                         goto found;
  445.                     }
  446.                 }
  447.             }
  448.             setvar(name, p, flag);
  449. found:;
  450.         }
  451.     } else {
  452.         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
  453.             for (vp = *vpp ; vp ; vp = vp->next) {
  454.                 if (vp->flags & flag) {
  455.                     for (p = vp->text ; *p != '=' ; p++)
  456.                         out1c(*p);
  457.                     out1c('\n');
  458.                 }
  459.             }
  460.         }
  461.     }
  462.     return 0;
  463. }
  464.  
  465.  
  466. /*
  467.  * The "local" command.
  468.  */
  469.  
  470. localcmd(argc, argv)  char **argv; {
  471.     char *name;
  472.  
  473.     if (! in_function())
  474.         error("Not in a function");
  475.     while ((name = *argptr++) != NULL) {
  476.         mklocal(name);
  477.     }
  478.     return 0;
  479. }
  480.  
  481.  
  482. /*
  483.  * Make a variable a local variable.  When a variable is made local, it's
  484.  * value and flags are saved in a localvar structure.  The saved values
  485.  * will be restored when the shell function returns.  We handle the name
  486.  * "-" as a special case.
  487.  */
  488.  
  489. void
  490. mklocal(name)
  491.     char *name;
  492.     {
  493.     struct localvar *lvp;
  494.     struct var **vpp;
  495.     struct var *vp;
  496.  
  497.     INTOFF;
  498.     lvp = ckmalloc(sizeof (struct localvar));
  499.     if (name[0] == '-' && name[1] == '\0') {
  500.         lvp->text = ckmalloc(sizeof optval);
  501.         bcopy(optval, lvp->text, sizeof optval);
  502.         vp = NULL;
  503.     } else {
  504.         vpp = hashvar(name);
  505.         for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
  506.         if (vp == NULL) {
  507.             if (strchr(name, '='))
  508.                 setvareq(savestr(name), VSTRFIXED);
  509.             else
  510.                 setvar(name, NULL, VSTRFIXED);
  511.             vp = *vpp;    /* the new variable */
  512.             lvp->text = NULL;
  513.             lvp->flags = VUNSET;
  514.         } else {
  515.             lvp->text = vp->text;
  516.             lvp->flags = vp->flags;
  517.             vp->flags |= VSTRFIXED|VTEXTFIXED;
  518.             if (strchr(name, '='))
  519.                 setvareq(savestr(name), 0);
  520.         }
  521.     }
  522.     lvp->vp = vp;
  523.     lvp->next = localvars;
  524.     localvars = lvp;
  525.     INTON;
  526. }
  527.  
  528.  
  529. /*
  530.  * Called after a function returns.
  531.  */
  532.  
  533. void
  534. poplocalvars() {
  535.     struct localvar *lvp;
  536.     struct var *vp;
  537.  
  538.     while ((lvp = localvars) != NULL) {
  539.         localvars = lvp->next;
  540.         vp = lvp->vp;
  541.         if (vp == NULL) {    /* $- saved */
  542.             bcopy(lvp->text, optval, sizeof optval);
  543.             ckfree(lvp->text);
  544.         } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
  545.             unsetvar(vp->text);
  546.         } else {
  547.             if ((vp->flags & VTEXTFIXED) == 0)
  548.                 ckfree(vp->text);
  549.             vp->flags = lvp->flags;
  550.             vp->text = lvp->text;
  551.         }
  552.         ckfree(lvp);
  553.     }
  554. }
  555.  
  556.  
  557. setvarcmd(argc, argv)  char **argv; {
  558.     if (argc <= 2)
  559.         return unsetcmd(argc, argv);
  560.     else if (argc == 3)
  561.         setvar(argv[1], argv[2], 0);
  562.     else
  563.         error("List assignment not implemented");
  564.     return 0;
  565. }
  566.  
  567.  
  568. /*
  569.  * The unset builtin command.  We unset the function before we unset the
  570.  * variable to allow a function to be unset when there is a readonly variable
  571.  * with the same name.
  572.  */
  573.  
  574. unsetcmd(argc, argv)  char **argv; {
  575.     char **ap;
  576.  
  577.     for (ap = argv + 1 ; *ap ; ap++) {
  578.         unsetfunc(*ap);
  579.         unsetvar(*ap);
  580.     }
  581.     return 0;
  582. }
  583.  
  584.  
  585. /*
  586.  * Unset the specified variable.
  587.  */
  588.  
  589. STATIC void
  590. unsetvar(s)
  591.     char *s;
  592.     {
  593.     struct var **vpp;
  594.     struct var *vp;
  595.  
  596.     vpp = hashvar(s);
  597.     for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
  598.         if (varequal(vp->text, s)) {
  599.             INTOFF;
  600.             if (*(strchr(vp->text, '=') + 1) != '\0'
  601.              || vp->flags & VREADONLY) {
  602.                 setvar(s, nullstr, 0);
  603.             }
  604.             vp->flags &=~ VEXPORT;
  605.             vp->flags |= VUNSET;
  606.             if ((vp->flags & VSTRFIXED) == 0) {
  607.                 if ((vp->flags & VTEXTFIXED) == 0)
  608.                     ckfree(vp->text);
  609.                 *vpp = vp->next;
  610.                 ckfree(vp);
  611.             }
  612.             INTON;
  613.             return;
  614.         }
  615.     }
  616. }
  617.  
  618.  
  619.  
  620. /*
  621.  * Find the appropriate entry in the hash table from the name.
  622.  */
  623.  
  624. STATIC struct var **
  625. hashvar(p)
  626.     register char *p;
  627.     {
  628.     unsigned int hashval;
  629.  
  630.     hashval = *p << 4;
  631.     while (*p && *p != '=')
  632.         hashval += *p++;
  633.     return &vartab[hashval % VTABSIZE];
  634. }
  635.  
  636.  
  637.  
  638. /*
  639.  * Returns true if the two strings specify the same varable.  The first
  640.  * variable name is terminated by '='; the second may be terminated by
  641.  * either '=' or '\0'.
  642.  */
  643.  
  644. STATIC int
  645. varequal(p, q)
  646.     register char *p, *q;
  647.     {
  648.     while (*p == *q++) {
  649.         if (*p++ == '=')
  650.             return 1;
  651.     }
  652.     if (*p == '=' && *(q - 1) == '\0')
  653.         return 1;
  654.     return 0;
  655. }
  656.